package com.ssy.lingxi.pay.serviceimpl.assetAccount;

import com.ssy.lingxi.common.constant.member.MemberLevelTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.vo.PageVO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.message.api.constant.MessageTemplateCode;
import com.ssy.lingxi.message.api.feign.SystemMessageControllerFeign;
import com.ssy.lingxi.message.api.vo.request.SystemMessageRequest;
import com.ssy.lingxi.pay.api.dto.request.assetAccount.CheckRequest;
import com.ssy.lingxi.pay.api.dto.request.assetAccount.SimpleIdListRequest;
import com.ssy.lingxi.pay.common.TradeStatusEnum;
import com.ssy.lingxi.pay.entity.assetAccount.AccountCashOutRecord;
import com.ssy.lingxi.pay.entity.assetAccount.AccountTradeRecord;
import com.ssy.lingxi.pay.entity.assetAccount.MemberAssetAccount;
import com.ssy.lingxi.pay.model.assetAccount.CashOutQueryQuery;
import com.ssy.lingxi.pay.repository.assetAccount.AccountCashOutRecordRepository;
import com.ssy.lingxi.pay.repository.assetAccount.AccountTradeRecordRepository;
import com.ssy.lingxi.pay.repository.assetAccount.MemberAssetAccountRepository;
import com.ssy.lingxi.pay.service.assetAccount.IAccountTradeService;
import com.ssy.lingxi.pay.service.assetAccount.IMemberAssetAccountService;
import com.ssy.lingxi.report.api.enums.AccountOperateTypeEnum;
import com.ssy.lingxi.report.api.enums.OperateDataSourceEnum;
import com.ssy.lingxi.report.api.feign.ReportControllerFeign;
import com.ssy.lingxi.report.api.vo.request.OperateNoticeVO;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 会员资金账户
 * @author jw.chen
 * @version 2.0.0
 * @date 2020/7/21
 */
@Service
public class AccountTradeServiceImpl implements IAccountTradeService {

    @Resource
    private MemberAssetAccountRepository memberAssetAccountRepository;

    @Resource
    private AccountTradeRecordRepository accountTradeRecordRepository;

    @Resource
    private AccountCashOutRecordRepository accountCashOutRecordRepository;

    @Resource
    private ReportControllerFeign reportControllerFeign;

    @Resource
    private IMemberAssetAccountService memberAssetAccountService;

    @Resource
    private SystemMessageControllerFeign systemMessageControllerFeign;

    /**
     * 查询会员资金账户交易记录
     * @return
     */
    @Override
    public Page<AccountTradeRecord> getAccountTradeRecord(PageVO pageVO, Long memberAssetAccountId) {
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize());
        return accountTradeRecordRepository.findByMemberAssetAccountIdOrderByTradeTimeDesc(memberAssetAccountId, page);
    }

    /**
     * 查询会员资金账户交易记录
     * @return
     */
    @Override
    public Page<AccountTradeRecord> getAccountTradeRecordList(PageVO pageVO, Long memberAssetAccountId, List<Integer> operationList, Long startTime, Long endTime) {
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize());
        return accountTradeRecordRepository.findByMemberAssetAccountIdAndOperationInAndTradeTimeGreaterThanEqualAndTradeTimeLessThanEqualOrderByTradeTimeDesc(memberAssetAccountId, operationList, startTime, endTime, page);
    }

    /**
     * 待审核提现
     * @param cashOutQueryQuery
     */
    @Override
    public Page<AccountTradeRecord> getCheckCashOutList(PageVO pageVO, CashOutQueryQuery cashOutQueryQuery) {
        Sort sort = Sort.by("tradeTime").descending();
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), sort);
        return accountTradeRecordRepository.findAll(getAccountCheckSpecification(cashOutQueryQuery), page);
    }

    /**
     * 批量审核
     * @param simpleIdListRequest
     */
    @Override
    public String batchCheck(SimpleIdListRequest simpleIdListRequest) {
        List<Long> idList = simpleIdListRequest.getIdList();
        List<AccountTradeRecord> accountTradeRecordList = accountTradeRecordRepository.findAllById(idList);
        List<AccountCashOutRecord> accountCashOutRecordList = new ArrayList<>();
        accountTradeRecordList.forEach(accountTradeRecord -> {
            Integer status = accountTradeRecord.getStatus();
            if (!TradeStatusEnum.ApplyCashOut.getCode().equals(status)) {
                throw new BusinessException(ResponseCode.PAY_MEMBER_ASSET_ACCOUNT_STATUS_EXCEPTION);
            } else {
                MemberAssetAccount memberAssetAccount = accountTradeRecord.getMemberAssetAccount();
                //统一校验账号
                memberAssetAccountService.checkMemberAssetAccount(memberAssetAccount);

                Double lock = memberAssetAccount.getLockBalance();
                Double account = memberAssetAccount.getAccountBalance();
                //四舍五入，保留两位小数
                DecimalFormat decimalFormat = new DecimalFormat("#.00");
                Double accountBalanceMoney = Double.parseDouble(decimalFormat.format(account - lock));
                memberAssetAccount.setAccountBalance(accountBalanceMoney);
                memberAssetAccount.setAccountBalanceEncrypt(DigestUtils.md5DigestAsHex(String.valueOf(accountBalanceMoney).getBytes()));
                //锁定金额清0
                Double defaultMoney = 0.00;
                String defaultMoneyEncrypt = DigestUtils.md5DigestAsHex(String.valueOf(defaultMoney).getBytes());
                memberAssetAccount.setLockBalance(defaultMoney);
                memberAssetAccount.setLockBalanceEncrypt(defaultMoneyEncrypt);
                memberAssetAccountRepository.saveAndFlush(memberAssetAccount);

                //首页数据统计
                try {
                    //待审核提现
                    List<OperateNoticeVO> operateNoticeVOList = new ArrayList<>();
                    OperateNoticeVO operateNoticeVO = new OperateNoticeVO();
                    operateNoticeVO.setMemberId(memberAssetAccount.getParentMemberId());
                    operateNoticeVO.setRoleId(memberAssetAccount.getParentMemberRoleId());
                    operateNoticeVO.setDataSource(OperateDataSourceEnum.ACCOUNT.getCode());
                    operateNoticeVO.setReduceOperateType(AccountOperateTypeEnum.TO_BE_VALIFY_CASHOUT.getCode());
                    operateNoticeVO.setReduceCount(1L);
                    operateNoticeVOList.add(operateNoticeVO);
                    //待支付提现
                    operateNoticeVO.setIncreaseOperateType(AccountOperateTypeEnum.TO_BE_PAY_CASHOUT.getCode());
                    operateNoticeVO.setIncreaseCount(1L);
                    operateNoticeVOList.add(operateNoticeVO);
                    reportControllerFeign.addOperateNoticeList(operateNoticeVOList);

                    //发送消息
                    // 待支付提现消息
                    SystemMessageRequest waitWithdrawMessage = new SystemMessageRequest();
                    if (MemberLevelTypeEnum.PLATFORM.getCode().equals(memberAssetAccount.getMemberLevelType())) {
                        waitWithdrawMessage.setMemberId(0L);
                        waitWithdrawMessage.setRoleId(0L);
                        waitWithdrawMessage.setMessageNotice(MessageTemplateCode.withdraw_platform_payment);
                        waitWithdrawMessage.setParams(Collections.singletonList(memberAssetAccount.getMemberName()));
                    } else {
                        waitWithdrawMessage.setMemberId(memberAssetAccount.getParentMemberId());
                        waitWithdrawMessage.setRoleId(memberAssetAccount.getParentMemberRoleId());
                        waitWithdrawMessage.setMessageNotice(MessageTemplateCode.withdraw_payment);
                        waitWithdrawMessage.setParams(Collections.singletonList(memberAssetAccount.getMemberName()));
                    }
                    // 提现申请审核消息
                    SystemMessageRequest applyAuditResultMessage = new SystemMessageRequest();
                    applyAuditResultMessage.setMemberId(memberAssetAccount.getMemberId());
                    applyAuditResultMessage.setRoleId(memberAssetAccount.getMemberRoleId());
                    applyAuditResultMessage.setMessageNotice(MessageTemplateCode.withdraw_apply);
                    applyAuditResultMessage.setParams(Collections.singletonList(TradeStatusEnum.CheckPass.getMessage()));
                    systemMessageControllerFeign.batchSendSystemMessage(Arrays.asList(waitWithdrawMessage, applyAuditResultMessage));
                } catch (Exception e) {
                    e.printStackTrace();
                }

                accountTradeRecord.setStatus(TradeStatusEnum.CheckPass.getCode());
                //提现处理记录
                AccountCashOutRecord accountCashOutRecord = new AccountCashOutRecord();
                accountCashOutRecord.setTradeCode(accountTradeRecord.getTradeCode());
                accountCashOutRecord.setTradeMoney(accountTradeRecord.getTradeMoney());
                accountCashOutRecord.setOperation(accountTradeRecord.getOperation());
                accountCashOutRecord.setRemark("同意提现");
                accountCashOutRecord.setStatus(TradeStatusEnum.CheckPass.getCode());
                accountCashOutRecord.setTradeTime(System.currentTimeMillis());
                accountCashOutRecordList.add(accountCashOutRecord);
            }
        });
        //保存提现处理记录
        accountCashOutRecordRepository.saveAll(accountCashOutRecordList);
        //保存资金账户信息
        accountTradeRecordRepository.saveAll(accountTradeRecordList);
        return "操作成功";
    }

    /**
     * 审核提现
     * @param checkRequest
     */
    @Transactional
    @Override
    public String check(CheckRequest checkRequest) {
        Long id = checkRequest.getId();
        Integer status = checkRequest.getStatus();
        Integer tradeStatus;
        if (status == 1) {
            tradeStatus = TradeStatusEnum.CheckPass.getCode();
        } else {
            tradeStatus = TradeStatusEnum.CheckNotPass.getCode();
        }
        String remark = checkRequest.getRemark();
        AccountTradeRecord accountTradeRecord = accountTradeRecordRepository.findById(id).orElse(null);
        if (accountTradeRecord != null) {
            Double tradeMoney = accountTradeRecord.getTradeMoney();
            MemberAssetAccount memberAssetAccount = accountTradeRecord.getMemberAssetAccount();
            //统一校验账号
            memberAssetAccountService.checkMemberAssetAccount(memberAssetAccount);

            Double lock = memberAssetAccount.getLockBalance();
            Double account = memberAssetAccount.getAccountBalance();
            //四舍五入，保留两位小数
            DecimalFormat decimalFormat = new DecimalFormat("#.00");

            //审核不通过，锁定资金返回到账号余额里面
            if (TradeStatusEnum.CheckNotPass.getCode().equals(tradeStatus)) {
                //锁定金额-交易金额
                Double lockMoney = Double.parseDouble(decimalFormat.format(lock - tradeMoney));
                String lockMoneyEncrypt = DigestUtils.md5DigestAsHex(String.valueOf(lockMoney).getBytes());
                memberAssetAccount.setLockBalance(lockMoney);
                memberAssetAccount.setLockBalanceEncrypt(lockMoneyEncrypt);
                memberAssetAccountRepository.saveAndFlush(memberAssetAccount);

                try {
                    //待审核提现
                    OperateNoticeVO operateNoticeVO = new OperateNoticeVO();
                    operateNoticeVO.setMemberId(memberAssetAccount.getParentMemberId());
                    operateNoticeVO.setRoleId(memberAssetAccount.getParentMemberRoleId());
                    operateNoticeVO.setDataSource(OperateDataSourceEnum.ACCOUNT.getCode());
                    operateNoticeVO.setReduceOperateType(AccountOperateTypeEnum.TO_BE_VALIFY_CASHOUT.getCode());
                    operateNoticeVO.setReduceCount(1L);
                    reportControllerFeign.addOperateNotice(operateNoticeVO);

                    //发送消息
                    // 提现申请审核消息
                    SystemMessageRequest applyAuditResultMessage = new SystemMessageRequest();
                    applyAuditResultMessage.setMemberId(memberAssetAccount.getMemberId());
                    applyAuditResultMessage.setRoleId(memberAssetAccount.getMemberRoleId());
                    applyAuditResultMessage.setMessageNotice(MessageTemplateCode.withdraw_apply);
                    applyAuditResultMessage.setParams(Collections.singletonList(TradeStatusEnum.CheckNotPass.getMessage()));
                    systemMessageControllerFeign.sendSystemMessage(applyAuditResultMessage);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else if (TradeStatusEnum.CheckPass.getCode().equals(tradeStatus)) {   //审核通过
                //账号金额-交易金额
                Double accountBalanceMoney = Double.parseDouble(decimalFormat.format(account - tradeMoney));
                memberAssetAccount.setAccountBalance(accountBalanceMoney);
                memberAssetAccount.setAccountBalanceEncrypt(DigestUtils.md5DigestAsHex(String.valueOf(accountBalanceMoney).getBytes()));
                //锁定金额-交易金额
                Double lockMoney = Double.parseDouble(decimalFormat.format(lock - tradeMoney));
                String lockMoneyEncrypt = DigestUtils.md5DigestAsHex(String.valueOf(lockMoney).getBytes());
                memberAssetAccount.setLockBalance(lockMoney);
                memberAssetAccount.setLockBalanceEncrypt(lockMoneyEncrypt);
                memberAssetAccountRepository.saveAndFlush(memberAssetAccount);

                //首页数据统计
                try {
                    //待审核提现
                    List<OperateNoticeVO> operateNoticeVOList = new ArrayList<>();
                    OperateNoticeVO operateNoticeVO = new OperateNoticeVO();
                    operateNoticeVO.setMemberId(memberAssetAccount.getParentMemberId());
                    operateNoticeVO.setRoleId(memberAssetAccount.getParentMemberRoleId());
                    operateNoticeVO.setDataSource(OperateDataSourceEnum.ACCOUNT.getCode());
                    operateNoticeVO.setReduceOperateType(AccountOperateTypeEnum.TO_BE_VALIFY_CASHOUT.getCode());
                    operateNoticeVO.setReduceCount(1L);
                    operateNoticeVOList.add(operateNoticeVO);
                    //待支付提现
                    operateNoticeVO = new OperateNoticeVO();
                    operateNoticeVO.setMemberId(memberAssetAccount.getParentMemberId());
                    operateNoticeVO.setRoleId(memberAssetAccount.getParentMemberRoleId());
                    operateNoticeVO.setDataSource(OperateDataSourceEnum.ACCOUNT.getCode());
                    operateNoticeVO.setIncreaseOperateType(AccountOperateTypeEnum.TO_BE_PAY_CASHOUT.getCode());
                    operateNoticeVO.setIncreaseCount(1L);
                    operateNoticeVOList.add(operateNoticeVO);
                    reportControllerFeign.addOperateNoticeList(operateNoticeVOList);

                    //发送消息
                    // 待支付提现消息
                    SystemMessageRequest waitWithdrawMessage = new SystemMessageRequest();
                    if (MemberLevelTypeEnum.PLATFORM.getCode().equals(memberAssetAccount.getMemberLevelType())) {
                        waitWithdrawMessage.setMemberId(0L);
                        waitWithdrawMessage.setRoleId(0L);
                        waitWithdrawMessage.setMessageNotice(MessageTemplateCode.withdraw_platform_payment);
                        waitWithdrawMessage.setParams(Collections.singletonList(memberAssetAccount.getMemberName()));
                    } else {
                        waitWithdrawMessage.setMemberId(memberAssetAccount.getParentMemberId());
                        waitWithdrawMessage.setRoleId(memberAssetAccount.getParentMemberRoleId());
                        waitWithdrawMessage.setMessageNotice(MessageTemplateCode.withdraw_payment);
                        waitWithdrawMessage.setParams(Collections.singletonList(memberAssetAccount.getMemberName()));
                    }
                    // 提现申请审核消息
                    SystemMessageRequest applyAuditResultMessage = new SystemMessageRequest();
                    applyAuditResultMessage.setMemberId(memberAssetAccount.getMemberId());
                    applyAuditResultMessage.setRoleId(memberAssetAccount.getMemberRoleId());
                    applyAuditResultMessage.setMessageNotice(MessageTemplateCode.withdraw_apply);
                    applyAuditResultMessage.setParams(Collections.singletonList(TradeStatusEnum.CheckPass.getMessage()));
                    systemMessageControllerFeign.batchSendSystemMessage(Arrays.asList(waitWithdrawMessage, applyAuditResultMessage));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            //保存交易记录
            accountTradeRecord.setStatus(tradeStatus);
            accountTradeRecord.setRemark(remark);
            accountTradeRecordRepository.saveAndFlush(accountTradeRecord);
            //保存提现处理记录
            AccountCashOutRecord accountCashOutRecord = new AccountCashOutRecord();
            accountCashOutRecord.setTradeCode(accountTradeRecord.getTradeCode());
            accountCashOutRecord.setTradeMoney(accountTradeRecord.getTradeMoney());
            accountCashOutRecord.setOperation(accountTradeRecord.getOperation());
            accountCashOutRecord.setRemark(remark);
            accountCashOutRecord.setStatus(tradeStatus);
            accountCashOutRecord.setTradeTime(System.currentTimeMillis());
            accountCashOutRecordRepository.saveAndFlush(accountCashOutRecord);

            return "操作成功";
        }
        throw new BusinessException(ResponseCode.PAY_MEMBER_ASSET_ACCOUNT_PAY_NOT_EXIST);
    }

    /**
     * 构建查询条件
     * @param cashOutQueryQuery
     * @return
     */
    private Specification<AccountTradeRecord> getAccountCheckSpecification(CashOutQueryQuery cashOutQueryQuery) {
        return (Specification<AccountTradeRecord>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            Predicate finalConditions = criteriaBuilder.conjunction();

            String memberName = cashOutQueryQuery.getMemberName();
            Long parentMemberId = cashOutQueryQuery.getParentMemberId();
            Long parentMemberRoleId = cashOutQueryQuery.getParentMemberRoleId();
            Long startTime = cashOutQueryQuery.getStartTime();
            Long endTime = cashOutQueryQuery.getEndTime();
            List<Integer> statusList = cashOutQueryQuery.getStatusList();
            List<Integer> memberLevelTypeList = cashOutQueryQuery.getMemberLevelTypeList();

            //会员名称
            if (!StringUtils.isEmpty(memberName)) {
                finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.like(root.get("memberAssetAccount").get("memberName").as(String.class), "%" + memberName + "%"));
            }
            //父级会员id
            if (parentMemberId != null && parentMemberId > 0) {
                finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.equal(root.get("memberAssetAccount").get("parentMemberId"), parentMemberId));
            }
            //父级会员角色id
            if (parentMemberRoleId != null && parentMemberRoleId > 0) {
                finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.equal(root.get("memberAssetAccount").get("parentMemberRoleId"), parentMemberRoleId));
            }
            //开始时间
            if (startTime != null && startTime > 0) {
                finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.ge(root.get("tradeTime"), startTime));
            }
            //结束时间
            if (endTime != null && endTime > 0) {
                finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.le(root.get("tradeTime"), endTime));
            }
            //状态
            if (statusList != null && !statusList.isEmpty()) {
                finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.in(root.get("status")).value(statusList));
            }
            //会员等级类型
            if (memberLevelTypeList != null && !memberLevelTypeList.isEmpty()) {
                finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.in(root.get("memberAssetAccount").get("memberLevelType")).value(memberLevelTypeList));
            }
            return finalConditions;
        };
    }

}

